package com.zilu.digitaltwin.common.manager;

import com.alibaba.cosmo.remote.httpclient.HttpMethod;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import com.aliyun.dataq.service.dbus.signature.DaasClient;
import com.aliyun.dataq.service.dbus.signature.DataQService;
import com.zilu.digitaltwin.common.exception.CommonErrorCode;
import com.zilu.digitaltwin.common.exception.CommonException;
import com.zilu.digitaltwin.common.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author :caijianbao
 * @date : 2023/1/2 22:28
 */
@Component
public class DataQManager {

    private static final Logger log = LoggerFactory.getLogger(DataQManager.class);


    @Value("${dataq.api.url}")
    private String dataQApiUrl;

    @Value("${dataq.application.code}")
    private String applicationCode;

    @Value("${dataq.openApi.access-id}")
    private String openApiAccessId;

    @Value("${dataq.openApi.access-key}")
    private String openApiAccesskey;

    @Value("${dataq.openApi.authenticationWay}")
    private String authenticationWay;

    private static final String SIMPLE_AUTHENTICATION_WAY = "simple";

    @Value("${dataq.workspace.code}")
    private String workspaceCode;


    /**
     * 调用dataQ统一服务接口
     *
     * @param method
     * @param apiName 接口的路径名
     * @param queryParam
     * @param requestBody
     * @return
     */
    public JSONObject sendByApiName(HttpMethod method, String apiName, Map<String, Object> queryParam, JSONObject requestBody) {
        String pathUrl = workspaceCode + "/" + applicationCode + "/" + apiName;
        return this.sendDataQApi(method, pathUrl, queryParam, requestBody, null);
    }


    /**
     * 调用dataQ接口
     *
     * @param method
     * @param pathUrl 不需要加/前缀
     * @param queryParam
     * @param requestBody
     * @param headerMap
     * @return
     */
    public JSONObject sendDataQApi(HttpMethod method, String pathUrl, Map<String, Object> queryParam, JSONObject requestBody, Map<String, Object> headerMap) {
        if (SIMPLE_AUTHENTICATION_WAY.equals(this.authenticationWay)) {
            return this.sendDataQApiForSimple(method, pathUrl, queryParam, requestBody, headerMap);
        } else {
            return this.sendDataQApiForComplete(method, pathUrl, queryParam, requestBody, headerMap);
        }
    }


    /**
     * 简单鉴权
     *
     * @param method
     * @param pathUrl
     * @param queryParam
     * @param requestBody
     * @param headerMap
     * @return
     */
    private JSONObject sendDataQApiForSimple(HttpMethod method, String pathUrl, Map<String, Object> queryParam, JSONObject requestBody, Map<String, Object> headerMap) {
        DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        headerMap.put("Date", DateUtil.getUTCTimeStr(df));
        headerMap.put("Accept", "application/json");
        headerMap.put("Content-Type", "application/json;charset=utf-8");
        headerMap.put("Authorization", applicationCode + " " + openApiAccessId);
        JSONObject resObj;
        if (HttpMethod.POST.equals(method)) {
            resObj = this.postDataQApi(pathUrl, queryParam, requestBody, headerMap);
        } else {
            resObj = this.getDataQApi(pathUrl, queryParam, headerMap);
        }

        if (!"SUCCESS".equalsIgnoreCase(resObj.getString("code"))) {
            throw new CommonException(CommonErrorCode.SERVER_ERROR, pathUrl + " 调用dataQ获取数据发生异常,code:ERROR,message:" + resObj.getString("message") + ", status:" + resObj.getString("status"));
        } else {
            return resObj;
        }
    }

    /**
     * 简单鉴权 get
     *
     * @param urlPath
     * @param paramMap
     * @param headerMap
     * @return
     */
    public JSONObject getDataQApi(String urlPath, Map<String, Object> paramMap, Map<String, Object> headerMap) {
        String url = dataQApiUrl + urlPath;
        log.info("调用dataQ获取数据: url={}, paramMap={}, headerMap={}", new Object[]{url, paramMap.toString(), headerMap.toString()});

        String response;
        try {
            response = HttpClientManager.sendGet(url, paramMap, headerMap);
        } catch (Exception e) {
            log.error("调用dataQ获取数据失败：url={}, 失败原因{}", url, e);
            throw new CommonException(CommonErrorCode.SERVER_ERROR, "调用dataQ获取数据失败,url:" + url + ", paramMap:" + paramMap.toString() + ", e:" + e.getMessage());
        }

        JSONObject resObj = JSON.parseObject(response);
        return resObj;
    }

    /**
     * 简单鉴权 post
     *
     * @param urlPath
     * @param paramMap
     * @param requestBody
     * @param headerMap
     * @return
     */
    private JSONObject postDataQApi(String urlPath, Map<String, Object> paramMap, JSONObject requestBody, Map<String, Object> headerMap) {
        String url = dataQApiUrl + urlPath;
        String requestStr = "";
        if (paramMap != null) {
            requestStr = paramMap.toString();
        } else if (requestBody != null) {
            requestStr = requestBody.toString();
        }

        log.info("调用dataQ获取数据: url={}, requestStr={}, headerMap={}", new Object[]{url, requestStr, headerMap.toString()});
        String response;
        try {
            response = HttpClientManager.sendPost(url, paramMap, requestBody, headerMap);
        } catch (Exception e) {
            log.error("调用dataQ获取数据失败：url={}, 失败原因{}", url, e);
            throw new CommonException(CommonErrorCode.SERVER_ERROR, "调用dataQ获取数据失败,url:" + url + ", requestStr:" + requestStr + ", e:" + e.getMessage());
        }

        JSONObject resObj = JSON.parseObject(response);
        return resObj;
    }

    /**
     * 完整鉴权
     *
     * @param method
     * @param pathUrl
     * @param queryParam
     * @param requestBody
     * @param headerMap
     * @return
     */
    private JSONObject sendDataQApiForComplete(HttpMethod method, String pathUrl, Map<String, Object> queryParam, JSONObject requestBody, Map<String, Object> headerMap) {
        DataQService.Builder builder = new DataQService.Builder();
        builder.setPath(pathUrl);
        builder.setAccessKeyId(openApiAccessId);
        builder.setAccessKeySecret(openApiAccesskey);
        builder.setModuleName(applicationCode);
        String requestStr;
        if (HttpMethod.POST.equals(method)) {
            builder.setRequestBody(requestBody);
            requestStr = requestBody.toString();
        } else {
            builder.addQueryParam(queryParam);
            requestStr = queryParam.toString();
        }
        if (headerMap == null) {
            headerMap = new HashMap<>(4);
        }
        headerMap.put("Accept", "application/json");
        headerMap.put("Content-Type", "application/json;charset=utf-8");
        builder.addHeader(headerMap);
        DataQService dataQService = builder.setHttpMethod(method).build();
        String endpoint = dataQApiUrl;
        DaasClient client = new DaasClient(endpoint);

        JSONObject resObj;
        try {
            Object response = client.invoke(dataQService, 60000, 300);
            resObj = JSON.parseObject((String) response);
        } catch (Exception e) {
            log.error("调用dataQ获取数据失败:url={}, AppKey={}, AppSecret={}, applicationCode={} ,params={}, 失败原因{}", new Object[]{endpoint + pathUrl, this.openApiAccessId, this.openApiAccesskey, this.applicationCode, requestStr, e});
            throw new CommonException(CommonErrorCode.SERVER_ERROR, "调用dataQ获取数据失败:url=" + endpoint + pathUrl + ", AppKey=" + this.openApiAccessId + ", AppSecret=" + this.openApiAccesskey + ", applicationCode=" + this.applicationCode + ", params =" + requestStr + ", 失败原因:" + e);
        }

        if (!"SUCCESS".equalsIgnoreCase(resObj.getString("code"))) {
            log.warn("调用dataQ获取数据失败:url={}, AppKey={}, AppSecret={}, applicationCode={} ,params={}, 失败原因:{}, status:{}", new Object[]{endpoint + pathUrl, this.openApiAccessId, this.openApiAccesskey, this.applicationCode, requestStr, resObj.getString("message"), resObj.getString("status")});
            throw new CommonException(CommonErrorCode.SERVER_ERROR, "调用dataQ获取数据失败:url=" + endpoint + pathUrl + ", AppKey=" + this.openApiAccessId + ", AppSecret=" + this.openApiAccesskey + ", applicationCode=" + this.applicationCode + ", params =" + requestStr + ", 失败原因:" + resObj.getString("message") + ", status" + resObj.getString("status"));
        } else {
            return resObj;
        }
    }


    public void validConfigMap(Long projectId, Map<String, String> configMap) {
        String tenant = configMap.get("tenant");
        String userId = configMap.get("user_id");
        String wsCode = configMap.get("workspace_code");
        String wsId = configMap.get("workspace_id");
        if (tenant == null || wsCode == null || userId == null || wsId == null) {
            log.warn("调用dataQ服务配置信息不完整, projectId:{}, tenant:{}, workspace_code:{}, workspace_id:{}, user_id:{}", new Object[]{projectId, tenant, wsCode, wsId, userId});
            throw new CommonException(CommonErrorCode.CONFIGURATION_EXCEPTION, "调用dataQ服务配置信息不完整, projectId:" + projectId + ",tenant:" + tenant + ",workspace_code:" + wsCode + ",workspace_id:" + wsId + ",user_id:" + userId);
        }
    }

}
